/*
 * This file is part of the openHiTLS project.
 *
 * openHiTLS is licensed under the Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *
 *     http://license.coscl.org.cn/MulanPSL2
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

#include "hitls_build.h"
#ifdef HITLS_CRYPTO_SM4

#include <stdlib.h>
#include "crypt_errno.h"
#include "crypt_utils.h"
#include "bsl_err_internal.h"
#include "crypt_sm4.h"

/* System parameter FK (originating GB/T 32907-2016 7.3 b or GM/T 0002-2012 7.3 2) */
static const uint32_t FK[] = {0xa3b1bac6, 0x56aa3350, 0x677d9197, 0xb27022dc};

/* Fixed parameter CK (originating GB/T 32907-2016 7.3 c or GM/T 0002-2012 7.3 3) */
static const uint32_t CK[] = {
    0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269, 0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9,
    0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249, 0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9,
    0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d, 0x141b2229, 0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299,
    0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209, 0x10171e25, 0x2c333a41, 0x484f565d, 0x646b7279,
};

/**
 * <<<: Cyclic shift to the left
 * ⊕: XOR
 * S-box: (originating GB/T 32907-2016 6.2 a or GM/T 0002-2012 6.2 1)
 * LE(B) = B⊕(B <<< 13)⊕(B <<< 23)
 * KBOX_0[i] = LE(SBOX[i])
 */
static const uint32_t KBOX_0[] = {
    0x6b1ac0d6, 0x48120090, 0x749d20e9, 0x7f1fc0fe, 0x661980cc, 0x709c20e1, 0x1e87a03d, 0x5b96e0b7,
    0x0b02c016, 0x5b16c0b6, 0x0a028014, 0x611840c2, 0x14050028, 0x7d9f60fb, 0x1605802c, 0x0280a005,
    0x1585602b, 0x338ce067, 0x4d13409a, 0x3b0ec076, 0x1505402a, 0x5f17c0be, 0x02008004, 0x619860c3,
    0x551540aa, 0x22088044, 0x09826013, 0x1304c026, 0x24892049, 0x4310c086, 0x0300c006, 0x4c932099,
    0x4e13809c, 0x21084042, 0x280a0050, 0x7a1e80f4, 0x48922091, 0x779de0ef, 0x4c130098, 0x3d0f407a,
    0x19866033, 0x2a0a8054, 0x0581600b, 0x21886043, 0x769da0ed, 0x6799e0cf, 0x561580ac, 0x310c4062,
    0x721c80e4, 0x599660b3, 0x0e03801c, 0x549520a9, 0x649920c9, 0x04010008, 0x741d00e8, 0x4a92a095,
    0x40100080, 0x6f9be0df, 0x4a128094, 0x7d1f40fa, 0x3a8ea075, 0x4791e08f, 0x1f87e03f, 0x5314c0a6,
    0x2388e047, 0x0380e007, 0x5394e0a7, 0x7e1f80fc, 0x799e60f3, 0x398e6073, 0x0b82e017, 0x5d1740ba,
    0x41906083, 0x2c8b2059, 0x1e07803c, 0x0c832019, 0x731cc0e6, 0x4290a085, 0x2789e04f, 0x541500a8,
    0x340d0068, 0x358d606b, 0x40902081, 0x591640b2, 0x388e2071, 0x320c8064, 0x6d1b40da, 0x4591608b,
    0x7c1f00f8, 0x759d60eb, 0x0781e00f, 0x2589604b, 0x380e0070, 0x2b0ac056, 0x4e93a09d, 0x1a86a035,
    0x0f03c01e, 0x12048024, 0x0701c00e, 0x2f0bc05e, 0x318c6063, 0x2c0b0058, 0x689a20d1, 0x511440a2,
    0x1284a025, 0x11044022, 0x3e0f807c, 0x1d87603b, 0x00802001, 0x10842021, 0x3c0f0078, 0x4390e087,
    0x6a1a80d4, 0x00000000, 0x2308c046, 0x2b8ae057, 0x4f93e09f, 0x699a60d3, 0x1384e027, 0x290a4052,
    0x2609804c, 0x1b06c036, 0x01004002, 0x739ce0e7, 0x501400a0, 0x621880c4, 0x641900c8, 0x4f13c09e,
    0x751d40ea, 0x5f97e0bf, 0x4511408a, 0x691a40d2, 0x20080040, 0x6398e0c7, 0x1c070038, 0x5a96a0b5,
    0x519460a3, 0x7b9ee0f7, 0x791e40f2, 0x6719c0ce, 0x7c9f20f9, 0x308c2061, 0x0a82a015, 0x509420a1,
    0x701c00e0, 0x5715c0ae, 0x2e8ba05d, 0x521480a4, 0x4d93609b, 0x1a068034, 0x0d03401a, 0x2a8aa055,
    0x5695a0ad, 0x49926093, 0x19064032, 0x18060030, 0x7a9ea0f5, 0x4611808c, 0x589620b1, 0x719c60e3,
    0x0e83a01d, 0x7b1ec0f6, 0x711c40e2, 0x1705c02e, 0x41104082, 0x330cc066, 0x651940ca, 0x300c0060,
    0x601800c0, 0x14852029, 0x11846023, 0x559560ab, 0x0681a00d, 0x298a6053, 0x2709c04e, 0x378de06f,
    0x6a9aa0d5, 0x6d9b60db, 0x1b86e037, 0x2288a045, 0x6f1bc0de, 0x7e9fa0fd, 0x4711c08e, 0x1785e02f,
    0x01806003, 0x7f9fe0ff, 0x350d406a, 0x390e4072, 0x368da06d, 0x360d806c, 0x2d8b605b, 0x288a2051,
    0x4691a08d, 0x0d83601b, 0x5795e0af, 0x49124092, 0x5d9760bb, 0x6e9ba0dd, 0x5e1780bc, 0x3f8fe07f,
    0x08822011, 0x6c9b20d9, 0x2e0b805c, 0x20882041, 0x0f83e01f, 0x08020010, 0x2d0b405a, 0x6c1b00d8,
    0x0501400a, 0x609820c1, 0x18862031, 0x44110088, 0x5294a0a5, 0x6699a0cd, 0x3d8f607b, 0x5e97a0bd,
    0x1685a02d, 0x3a0e8074, 0x681a00d0, 0x09024012, 0x5c1700b8, 0x729ca0e5, 0x5a1680b4, 0x581600b0,
    0x44912089, 0x348d2069, 0x4b92e097, 0x2509404a, 0x0601800c, 0x4b12c096, 0x3b8ee077, 0x3f0fc07e,
    0x328ca065, 0x5c9720b9, 0x789e20f1, 0x04812009, 0x6298a0c5, 0x370dc06e, 0x6318c0c6, 0x42108084,
    0x0c030018, 0x781e00f0, 0x3e8fa07d, 0x761d80ec, 0x1d07403a, 0x6e1b80dc, 0x2689a04d, 0x10040020,
    0x3c8f2079, 0x771dc0ee, 0x2f8be05f, 0x1f07c03e, 0x6b9ae0d7, 0x659960cb, 0x1c872039, 0x24090048,
};

/* KBOX_1[i] = KBOX_0[i] <<< 8 */
static const uint32_t KBOX_1[] = {
    0x1ac0d66b, 0x12009048, 0x9d20e974, 0x1fc0fe7f, 0x1980cc66, 0x9c20e170, 0x87a03d1e, 0x96e0b75b,
    0x02c0160b, 0x16c0b65b, 0x0280140a, 0x1840c261, 0x05002814, 0x9f60fb7d, 0x05802c16, 0x80a00502,
    0x85602b15, 0x8ce06733, 0x13409a4d, 0x0ec0763b, 0x05402a15, 0x17c0be5f, 0x00800402, 0x9860c361,
    0x1540aa55, 0x08804422, 0x82601309, 0x04c02613, 0x89204924, 0x10c08643, 0x00c00603, 0x9320994c,
    0x13809c4e, 0x08404221, 0x0a005028, 0x1e80f47a, 0x92209148, 0x9de0ef77, 0x1300984c, 0x0f407a3d,
    0x86603319, 0x0a80542a, 0x81600b05, 0x88604321, 0x9da0ed76, 0x99e0cf67, 0x1580ac56, 0x0c406231,
    0x1c80e472, 0x9660b359, 0x03801c0e, 0x9520a954, 0x9920c964, 0x01000804, 0x1d00e874, 0x92a0954a,
    0x10008040, 0x9be0df6f, 0x1280944a, 0x1f40fa7d, 0x8ea0753a, 0x91e08f47, 0x87e03f1f, 0x14c0a653,
    0x88e04723, 0x80e00703, 0x94e0a753, 0x1f80fc7e, 0x9e60f379, 0x8e607339, 0x82e0170b, 0x1740ba5d,
    0x90608341, 0x8b20592c, 0x07803c1e, 0x8320190c, 0x1cc0e673, 0x90a08542, 0x89e04f27, 0x1500a854,
    0x0d006834, 0x8d606b35, 0x90208140, 0x1640b259, 0x8e207138, 0x0c806432, 0x1b40da6d, 0x91608b45,
    0x1f00f87c, 0x9d60eb75, 0x81e00f07, 0x89604b25, 0x0e007038, 0x0ac0562b, 0x93a09d4e, 0x86a0351a,
    0x03c01e0f, 0x04802412, 0x01c00e07, 0x0bc05e2f, 0x8c606331, 0x0b00582c, 0x9a20d168, 0x1440a251,
    0x84a02512, 0x04402211, 0x0f807c3e, 0x87603b1d, 0x80200100, 0x84202110, 0x0f00783c, 0x90e08743,
    0x1a80d46a, 0x00000000, 0x08c04623, 0x8ae0572b, 0x93e09f4f, 0x9a60d369, 0x84e02713, 0x0a405229,
    0x09804c26, 0x06c0361b, 0x00400201, 0x9ce0e773, 0x1400a050, 0x1880c462, 0x1900c864, 0x13c09e4f,
    0x1d40ea75, 0x97e0bf5f, 0x11408a45, 0x1a40d269, 0x08004020, 0x98e0c763, 0x0700381c, 0x96a0b55a,
    0x9460a351, 0x9ee0f77b, 0x1e40f279, 0x19c0ce67, 0x9f20f97c, 0x8c206130, 0x82a0150a, 0x9420a150,
    0x1c00e070, 0x15c0ae57, 0x8ba05d2e, 0x1480a452, 0x93609b4d, 0x0680341a, 0x03401a0d, 0x8aa0552a,
    0x95a0ad56, 0x92609349, 0x06403219, 0x06003018, 0x9ea0f57a, 0x11808c46, 0x9620b158, 0x9c60e371,
    0x83a01d0e, 0x1ec0f67b, 0x1c40e271, 0x05c02e17, 0x10408241, 0x0cc06633, 0x1940ca65, 0x0c006030,
    0x1800c060, 0x85202914, 0x84602311, 0x9560ab55, 0x81a00d06, 0x8a605329, 0x09c04e27, 0x8de06f37,
    0x9aa0d56a, 0x9b60db6d, 0x86e0371b, 0x88a04522, 0x1bc0de6f, 0x9fa0fd7e, 0x11c08e47, 0x85e02f17,
    0x80600301, 0x9fe0ff7f, 0x0d406a35, 0x0e407239, 0x8da06d36, 0x0d806c36, 0x8b605b2d, 0x8a205128,
    0x91a08d46, 0x83601b0d, 0x95e0af57, 0x12409249, 0x9760bb5d, 0x9ba0dd6e, 0x1780bc5e, 0x8fe07f3f,
    0x82201108, 0x9b20d96c, 0x0b805c2e, 0x88204120, 0x83e01f0f, 0x02001008, 0x0b405a2d, 0x1b00d86c,
    0x01400a05, 0x9820c160, 0x86203118, 0x11008844, 0x94a0a552, 0x99a0cd66, 0x8f607b3d, 0x97a0bd5e,
    0x85a02d16, 0x0e80743a, 0x1a00d068, 0x02401209, 0x1700b85c, 0x9ca0e572, 0x1680b45a, 0x1600b058,
    0x91208944, 0x8d206934, 0x92e0974b, 0x09404a25, 0x01800c06, 0x12c0964b, 0x8ee0773b, 0x0fc07e3f,
    0x8ca06532, 0x9720b95c, 0x9e20f178, 0x81200904, 0x98a0c562, 0x0dc06e37, 0x18c0c663, 0x10808442,
    0x0300180c, 0x1e00f078, 0x8fa07d3e, 0x1d80ec76, 0x07403a1d, 0x1b80dc6e, 0x89a04d26, 0x04002010,
    0x8f20793c, 0x1dc0ee77, 0x8be05f2f, 0x07c03e1f, 0x9ae0d76b, 0x9960cb65, 0x8720391c, 0x09004824,
};

/* KBOX_2[i] = KBOX_0[i] <<< 16 */
static const uint32_t KBOX_2[] = {
    0xc0d66b1a, 0x00904812, 0x20e9749d, 0xc0fe7f1f, 0x80cc6619, 0x20e1709c, 0xa03d1e87, 0xe0b75b96,
    0xc0160b02, 0xc0b65b16, 0x80140a02, 0x40c26118, 0x00281405, 0x60fb7d9f, 0x802c1605, 0xa0050280,
    0x602b1585, 0xe067338c, 0x409a4d13, 0xc0763b0e, 0x402a1505, 0xc0be5f17, 0x80040200, 0x60c36198,
    0x40aa5515, 0x80442208, 0x60130982, 0xc0261304, 0x20492489, 0xc0864310, 0xc0060300, 0x20994c93,
    0x809c4e13, 0x40422108, 0x0050280a, 0x80f47a1e, 0x20914892, 0xe0ef779d, 0x00984c13, 0x407a3d0f,
    0x60331986, 0x80542a0a, 0x600b0581, 0x60432188, 0xa0ed769d, 0xe0cf6799, 0x80ac5615, 0x4062310c,
    0x80e4721c, 0x60b35996, 0x801c0e03, 0x20a95495, 0x20c96499, 0x00080401, 0x00e8741d, 0xa0954a92,
    0x00804010, 0xe0df6f9b, 0x80944a12, 0x40fa7d1f, 0xa0753a8e, 0xe08f4791, 0xe03f1f87, 0xc0a65314,
    0xe0472388, 0xe0070380, 0xe0a75394, 0x80fc7e1f, 0x60f3799e, 0x6073398e, 0xe0170b82, 0x40ba5d17,
    0x60834190, 0x20592c8b, 0x803c1e07, 0x20190c83, 0xc0e6731c, 0xa0854290, 0xe04f2789, 0x00a85415,
    0x0068340d, 0x606b358d, 0x20814090, 0x40b25916, 0x2071388e, 0x8064320c, 0x40da6d1b, 0x608b4591,
    0x00f87c1f, 0x60eb759d, 0xe00f0781, 0x604b2589, 0x0070380e, 0xc0562b0a, 0xa09d4e93, 0xa0351a86,
    0xc01e0f03, 0x80241204, 0xc00e0701, 0xc05e2f0b, 0x6063318c, 0x00582c0b, 0x20d1689a, 0x40a25114,
    0xa0251284, 0x40221104, 0x807c3e0f, 0x603b1d87, 0x20010080, 0x20211084, 0x00783c0f, 0xe0874390,
    0x80d46a1a, 0x00000000, 0xc0462308, 0xe0572b8a, 0xe09f4f93, 0x60d3699a, 0xe0271384, 0x4052290a,
    0x804c2609, 0xc0361b06, 0x40020100, 0xe0e7739c, 0x00a05014, 0x80c46218, 0x00c86419, 0xc09e4f13,
    0x40ea751d, 0xe0bf5f97, 0x408a4511, 0x40d2691a, 0x00402008, 0xe0c76398, 0x00381c07, 0xa0b55a96,
    0x60a35194, 0xe0f77b9e, 0x40f2791e, 0xc0ce6719, 0x20f97c9f, 0x2061308c, 0xa0150a82, 0x20a15094,
    0x00e0701c, 0xc0ae5715, 0xa05d2e8b, 0x80a45214, 0x609b4d93, 0x80341a06, 0x401a0d03, 0xa0552a8a,
    0xa0ad5695, 0x60934992, 0x40321906, 0x00301806, 0xa0f57a9e, 0x808c4611, 0x20b15896, 0x60e3719c,
    0xa01d0e83, 0xc0f67b1e, 0x40e2711c, 0xc02e1705, 0x40824110, 0xc066330c, 0x40ca6519, 0x0060300c,
    0x00c06018, 0x20291485, 0x60231184, 0x60ab5595, 0xa00d0681, 0x6053298a, 0xc04e2709, 0xe06f378d,
    0xa0d56a9a, 0x60db6d9b, 0xe0371b86, 0xa0452288, 0xc0de6f1b, 0xa0fd7e9f, 0xc08e4711, 0xe02f1785,
    0x60030180, 0xe0ff7f9f, 0x406a350d, 0x4072390e, 0xa06d368d, 0x806c360d, 0x605b2d8b, 0x2051288a,
    0xa08d4691, 0x601b0d83, 0xe0af5795, 0x40924912, 0x60bb5d97, 0xa0dd6e9b, 0x80bc5e17, 0xe07f3f8f,
    0x20110882, 0x20d96c9b, 0x805c2e0b, 0x20412088, 0xe01f0f83, 0x00100802, 0x405a2d0b, 0x00d86c1b,
    0x400a0501, 0x20c16098, 0x20311886, 0x00884411, 0xa0a55294, 0xa0cd6699, 0x607b3d8f, 0xa0bd5e97,
    0xa02d1685, 0x80743a0e, 0x00d0681a, 0x40120902, 0x00b85c17, 0xa0e5729c, 0x80b45a16, 0x00b05816,
    0x20894491, 0x2069348d, 0xe0974b92, 0x404a2509, 0x800c0601, 0xc0964b12, 0xe0773b8e, 0xc07e3f0f,
    0xa065328c, 0x20b95c97, 0x20f1789e, 0x20090481, 0xa0c56298, 0xc06e370d, 0xc0c66318, 0x80844210,
    0x00180c03, 0x00f0781e, 0xa07d3e8f, 0x80ec761d, 0x403a1d07, 0x80dc6e1b, 0xa04d2689, 0x00201004,
    0x20793c8f, 0xc0ee771d, 0xe05f2f8b, 0xc03e1f07, 0xe0d76b9a, 0x60cb6599, 0x20391c87, 0x00482409,
};

/* KBOX_3[i] = KBOX_0[i] <<< 24 */
static const uint32_t KBOX_3[] = {
    0xd66b1ac0, 0x90481200, 0xe9749d20, 0xfe7f1fc0, 0xcc661980, 0xe1709c20, 0x3d1e87a0, 0xb75b96e0,
    0x160b02c0, 0xb65b16c0, 0x140a0280, 0xc2611840, 0x28140500, 0xfb7d9f60, 0x2c160580, 0x050280a0,
    0x2b158560, 0x67338ce0, 0x9a4d1340, 0x763b0ec0, 0x2a150540, 0xbe5f17c0, 0x04020080, 0xc3619860,
    0xaa551540, 0x44220880, 0x13098260, 0x261304c0, 0x49248920, 0x864310c0, 0x060300c0, 0x994c9320,
    0x9c4e1380, 0x42210840, 0x50280a00, 0xf47a1e80, 0x91489220, 0xef779de0, 0x984c1300, 0x7a3d0f40,
    0x33198660, 0x542a0a80, 0x0b058160, 0x43218860, 0xed769da0, 0xcf6799e0, 0xac561580, 0x62310c40,
    0xe4721c80, 0xb3599660, 0x1c0e0380, 0xa9549520, 0xc9649920, 0x08040100, 0xe8741d00, 0x954a92a0,
    0x80401000, 0xdf6f9be0, 0x944a1280, 0xfa7d1f40, 0x753a8ea0, 0x8f4791e0, 0x3f1f87e0, 0xa65314c0,
    0x472388e0, 0x070380e0, 0xa75394e0, 0xfc7e1f80, 0xf3799e60, 0x73398e60, 0x170b82e0, 0xba5d1740,
    0x83419060, 0x592c8b20, 0x3c1e0780, 0x190c8320, 0xe6731cc0, 0x854290a0, 0x4f2789e0, 0xa8541500,
    0x68340d00, 0x6b358d60, 0x81409020, 0xb2591640, 0x71388e20, 0x64320c80, 0xda6d1b40, 0x8b459160,
    0xf87c1f00, 0xeb759d60, 0x0f0781e0, 0x4b258960, 0x70380e00, 0x562b0ac0, 0x9d4e93a0, 0x351a86a0,
    0x1e0f03c0, 0x24120480, 0x0e0701c0, 0x5e2f0bc0, 0x63318c60, 0x582c0b00, 0xd1689a20, 0xa2511440,
    0x251284a0, 0x22110440, 0x7c3e0f80, 0x3b1d8760, 0x01008020, 0x21108420, 0x783c0f00, 0x874390e0,
    0xd46a1a80, 0x00000000, 0x462308c0, 0x572b8ae0, 0x9f4f93e0, 0xd3699a60, 0x271384e0, 0x52290a40,
    0x4c260980, 0x361b06c0, 0x02010040, 0xe7739ce0, 0xa0501400, 0xc4621880, 0xc8641900, 0x9e4f13c0,
    0xea751d40, 0xbf5f97e0, 0x8a451140, 0xd2691a40, 0x40200800, 0xc76398e0, 0x381c0700, 0xb55a96a0,
    0xa3519460, 0xf77b9ee0, 0xf2791e40, 0xce6719c0, 0xf97c9f20, 0x61308c20, 0x150a82a0, 0xa1509420,
    0xe0701c00, 0xae5715c0, 0x5d2e8ba0, 0xa4521480, 0x9b4d9360, 0x341a0680, 0x1a0d0340, 0x552a8aa0,
    0xad5695a0, 0x93499260, 0x32190640, 0x30180600, 0xf57a9ea0, 0x8c461180, 0xb1589620, 0xe3719c60,
    0x1d0e83a0, 0xf67b1ec0, 0xe2711c40, 0x2e1705c0, 0x82411040, 0x66330cc0, 0xca651940, 0x60300c00,
    0xc0601800, 0x29148520, 0x23118460, 0xab559560, 0x0d0681a0, 0x53298a60, 0x4e2709c0, 0x6f378de0,
    0xd56a9aa0, 0xdb6d9b60, 0x371b86e0, 0x452288a0, 0xde6f1bc0, 0xfd7e9fa0, 0x8e4711c0, 0x2f1785e0,
    0x03018060, 0xff7f9fe0, 0x6a350d40, 0x72390e40, 0x6d368da0, 0x6c360d80, 0x5b2d8b60, 0x51288a20,
    0x8d4691a0, 0x1b0d8360, 0xaf5795e0, 0x92491240, 0xbb5d9760, 0xdd6e9ba0, 0xbc5e1780, 0x7f3f8fe0,
    0x11088220, 0xd96c9b20, 0x5c2e0b80, 0x41208820, 0x1f0f83e0, 0x10080200, 0x5a2d0b40, 0xd86c1b00,
    0x0a050140, 0xc1609820, 0x31188620, 0x88441100, 0xa55294a0, 0xcd6699a0, 0x7b3d8f60, 0xbd5e97a0,
    0x2d1685a0, 0x743a0e80, 0xd0681a00, 0x12090240, 0xb85c1700, 0xe5729ca0, 0xb45a1680, 0xb0581600,
    0x89449120, 0x69348d20, 0x974b92e0, 0x4a250940, 0x0c060180, 0x964b12c0, 0x773b8ee0, 0x7e3f0fc0,
    0x65328ca0, 0xb95c9720, 0xf1789e20, 0x09048120, 0xc56298a0, 0x6e370dc0, 0xc66318c0, 0x84421080,
    0x180c0300, 0xf0781e00, 0x7d3e8fa0, 0xec761d80, 0x3a1d0740, 0xdc6e1b80, 0x4d2689a0, 0x20100400,
    0x793c8f20, 0xee771dc0, 0x5f2f8be0, 0x3e1f07c0, 0xd76b9ae0, 0xcb659960, 0x391c8720, 0x48240900,
};

#define KROUND(t, k0, k1, k2, k3, ck, sbox, rki) \
    do {                                        \
        (t) = (k1) ^ (k2) ^ (k3) ^ (ck);        \
        (k0) ^= (sbox##_3)[((t) >> 24) & 0xff]; \
        (k0) ^= (sbox##_2)[((t) >> 16) & 0xff]; \
        (k0) ^= (sbox##_1)[((t) >> 8) & 0xff];  \
        (k0) ^= (sbox##_0)[(t) & 0xff];         \
        (rki) = (k0);                           \
    } while (0)

/* Generate a round key */
#define KROUND_FUNCTION(t, k0, k1, k2, k3, sbox, rk)                            \
    for (int i = 0; i < 32; i += 4) {                                           \
        KROUND((t), (k0), (k1), (k2), (k3), CK[(i) + 0], sbox, (rk)[(i) + 0]);  \
        KROUND((t), (k1), (k2), (k3), (k0), CK[(i) + 1], sbox, (rk)[(i) + 1]);  \
        KROUND((t), (k2), (k3), (k0), (k1), CK[(i) + 2], sbox, (rk)[(i) + 2]);  \
        KROUND((t), (k3), (k0), (k1), (k2), CK[(i) + 3], sbox, (rk)[(i) + 3]);  \
    }

int32_t CRYPT_SM4_SetKey(CRYPT_SM4_Ctx *ctx, const uint8_t *key, uint32_t keyLen)
{
    if (ctx == NULL || key == NULL) {
        BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
        return CRYPT_NULL_INPUT;
    }

    if (keyLen != CRYPT_SM4_BLOCKSIZE) {
        BSL_ERR_PUSH_ERROR(CRYPT_SM4_ERR_KEY_LEN);
        return CRYPT_SM4_ERR_KEY_LEN;
    }

    volatile uint32_t k0, k1, k2, k3;
    volatile uint32_t t;
    k0 = GET_UINT32_BE(key, 0) ^ FK[0];     // k0: 4 bytes starting from the 0th index of the key⊕FK[0]
    k1 = GET_UINT32_BE(key, 4) ^ FK[1];     // k1: 4 bytes starting from the 4th index of the key⊕FK[1]
    k2 = GET_UINT32_BE(key, 8) ^ FK[2];     // k2: 4 bytes starting from the 8th index of the key⊕FK[2]
    k3 = GET_UINT32_BE(key, 12) ^ FK[3];    // k3: 4 bytes starting from the 12th index of the key⊕FK[3]
    KROUND_FUNCTION(t, k0, k1, k2, k3, KBOX, ctx->rk);
    k0 = 0;
    k1 = 0;
    k2 = 0;
    k3 = 0;
    t = 0;
    return CRYPT_SUCCESS;
}
#endif // HITLS_CRYPTO_SM4
